/*
    Version: 0.1
    Module Memory:
        0> act as a ram pool
        1> responsible for store matrix data
        2> provide two operations: read and write
        3> signal: 
            clk  : clock signal
            addr : addr for read or write
            data : data for output or input
            cs   : chip select signal
            we   : write enable signal. 1: write. 0: read
            oe   : output enable. 1: output data to data_bus. 0: data_bus high-impedance
*/
module single_port_sync_ram
    # (parameter ADDR_WIDTH = 4,
       parameter DATA_WIDTH = 32,
       parameter DEPTH = 16
    )
    (   input 					clk,
        input [ADDR_WIDTH-1:0]	addr,
        inout [DATA_WIDTH-1:0]	data,
        input 					cs,
        input 					we,
        input 					oe
    );

    reg [DATA_WIDTH-1:0] 	tmp_data;
    reg [DATA_WIDTH-1:0] 	mem [0:DEPTH-1];

    /* 
     * write input data which width is DATA_WIDTH to a memory unit specified by addr
     * controlled by cs and we signals
     */
    always @ (posedge clk) begin
        if (cs & we) begin
            mem[addr] <= data;
            //$display("\n******[mem_top] write done===in_data 0x%h, mem[addr] 0x%h, addr %d", data, mem[addr], addr);
        end
    end
    /* 
     * read data from a memory unit specified by addr to the tmp_data
     * controlled by cs and !we and oe signals
     */
    always @ (posedge clk) begin
        if (cs & !we) begin
            tmp_data <= mem[addr];
            //$display("\n******[mem_top] read done===out_data 0x%h, tmp_data 0x%h, mem[addr] 0x%h, addr %d cs %d, oe %d, we %d", data, tmp_data, mem[addr], addr, cs, oe, we);
        end
    end

    /* continuous assignment to data controlled by cs and !we and oe, which acts as a read operation */
    assign data = (cs & oe & !we) ? tmp_data : {DATA_WIDTH{1'bz}};
endmodule
